using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Xml;

namespace PocketLibrary
{
    public class RESTCommunication
    {
        #region private methods

        private string ByteArrayToHexString(byte[] data)
        {
            StringBuilder sb = new StringBuilder(data.Length * 3);
            foreach (byte b in data)
                sb.Append(Convert.ToString(b, 16).PadLeft(2, '0'));
            return sb.ToString().ToLower();
        }

        private string SignRequest(string request)
        {
            //MD5 mymd5 = MD5.Create();
            //byte[] hash = mymd5.ComputeHash(Encoding.ASCII.GetBytes(request));
            //return ByteArrayToHexString(hash);
            System.Security.Cryptography.MD5CryptoServiceProvider csp = 
                new System.Security.Cryptography.MD5CryptoServiceProvider();

            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(request);
            byte[] hashedBytes = csp.ComputeHash(bytes, 0, bytes.Length);
            return BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
        }

        public static string StaticSignRequest(string request)
        {
            System.Security.Cryptography.MD5CryptoServiceProvider csp =
                new System.Security.Cryptography.MD5CryptoServiceProvider();

            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(request);
            byte[] hashedBytes = csp.ComputeHash(bytes, 0, bytes.Length);
            return BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
        }

        private HttpWebRequest CreateRequest(string uri)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
            //request.PreAuthenticate = true;
            request.ProtocolVersion = new Version("1.1");
            //request.SendChunked = false;
            request.UserAgent = "PocketApps 0.2";
            request.Method = this._method.ToUpper();
            //request.Credentials = new NetworkCredential(UserName, PassWord);

            //byte[] _basic = Encoding.ASCII.GetBytes(UserName + ":" + PassWord);
            //string _strbasic = Convert.ToBase64String(_basic);
            //request.Headers.Add("Authorization: Basic " + _strbasic);

            return request;
        }

        private string ReadResponseBody(HttpWebResponse response)
        {
            string body;

            Stream stream = response.GetResponseStream();

            StreamReader reader = new StreamReader(stream, Encoding.UTF8);

            body = reader.ReadToEnd();

            stream.Close();

            return body;
        }

        private void WriteRequestBody(HttpWebRequest request, string body)
        {
            byte[] bytes;

            bytes = Encoding.UTF8.GetBytes(body);

            request.ContentLength = bytes.Length;

            Stream stream = request.GetRequestStream();

            stream.Write(bytes, 0, bytes.Length);

            stream.Close();
        }
        #endregion

        #region private fields
        
        string _method = "GET";

        StringBuilder _requestString = new StringBuilder();
        StringBuilder _hashString = new StringBuilder();


        #endregion

        #region public fields
        private string _serviceUrl="";

        public string ServiceUrl
        {
            get { return _serviceUrl; }
            set { _serviceUrl = value; }
        }

        private SortedList<string, string> _params = new SortedList<string, string>();

        public SortedList<string, string> Parameters
        {
            get { return _params; }
            set { _params = value; }
        }

        private string _requestStringLeftPad;

        /// <summary>
        /// string to add to left side of hashstring
        /// </summary>
        public string LeftPad
        {
            get { return _requestStringLeftPad; }
            set { _requestStringLeftPad = value; }
        }

        private string _requestStringRightPad;

        public string RightPad
        {
            get { return _requestStringRightPad; }
            set { _requestStringRightPad = value; }
        }



        #endregion

        #region public methods

        public XmlDocument Execute()
        {
            return ExecuteGETRequest();
        }

        public XmlDocument ExecuteGETRequest()
        {
            this._method = "GET";

            string requestString = GenerateRequestString();

            HttpWebRequest request = this.CreateRequest(_serviceUrl + requestString);

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            XmlDocument returnedXml = new XmlDocument();
            returnedXml.LoadXml(this.ReadResponseBody(response));

            return returnedXml;
        }

        public string GenerateRequestString()
        {
            _requestString = new StringBuilder("?");
            _hashString = new StringBuilder(LeftPad);

            for (int i = 0; i < _params.Count; i++)
            {
                _requestString.Append(_params.Keys[i] + "=" + _params.Values[i]);
                if (i < _params.Count - 1)
                    _requestString.Append("&");
                _hashString.Append(_params.Keys[i] + _params.Values[i]);
            }

            string signature = SignRequest(_hashString.ToString());
            _requestString.Append("&api_sig=");
            _requestString.Append(signature);

            return _requestString.ToString();
        }

        public void ExecutePUTRequest()
        {
            this._method = "PUT";
        }

        public void ExecuteDELETERequest()
        {
            this._method = "DELETE";
        }

        public void ExecutePOSTRequest()
        {
            this._method = "POST";
        }
        #endregion 

    }
}
